package cn.edu.ecust.seckill.config;

import cn.edu.ecust.seckill.entity.Order;
import cn.edu.ecust.seckill.entity.Product;
import cn.edu.ecust.seckill.result.Result;
import jakarta.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

@Component
public class Scheduler {

    @Autowired
    ThreadPoolTaskScheduler threadPoolTaskScheduler;
    @Autowired
    RedisTemplate<String,Object> redisTemplate;
    @Autowired
    List<TaskQueue> taskQueueList;

    /**
     * 定时任务批量执行
     * 没参与过 有库存
     * 下单
     */
    @PostConstruct
    public void init() {
        for (TaskQueue taskQueue : taskQueueList) {
            threadPoolTaskScheduler.scheduleAtFixedRate(() -> {
                // 获取当前任务列表
                List<Task> taskList = taskQueue.takeAll();
                // 没参与过
                List<Object> flagList = redisTemplate.executePipelined((RedisCallback<Object>) connection -> {
                    for(Task task : taskList) {
                        connection.setNX(("seckill:" + task.getProductId() + ":user:" + task.getUserId()).getBytes(StandardCharsets.UTF_8), "1".getBytes(StandardCharsets.UTF_8));
                    }
                    return null;
                });
                for (int i = 0; i < taskList.size(); i++) {
                    Task task = taskList.get(i);
                    Boolean flag = (Boolean) flagList.get(i);
                    if(!flag){
                        task.getCompletableFuture().complete(Result.fail(401, "您已参与过该次秒杀，请耐心等待结果"));
                    }
                }
                taskList.remove(taskList.stream().filter(task -> task.getCompletableFuture().isDone()).collect(Collectors.toList()));
                if(CollectionUtils.isEmpty(taskList)) {
                    return;
                }
                // 有库存
                Long decrement = redisTemplate.opsForValue().decrement("seckill:" + taskList.get(0).getProductId() + ":inventory", taskList.size());
                for (int i = 0; i < taskList.size(); i++) {
                    Task task = taskList.get(i);
                    if(i > taskList.size() + decrement) {
                        task.getCompletableFuture().complete(Result.fail(401, "该商品已被抢购完，再接再厉吧"));
                    }
                }
                taskList.remove(taskList.stream().filter(task -> task.getCompletableFuture().isDone()).collect(Collectors.toList()));
                if(CollectionUtils.isEmpty(taskList)) {
                    return;
                }
                // 创建订单
                Product product = (Product) redisTemplate.opsForValue().get("product:" + taskList.get(0).getProductId());
                List<Order> orderList = taskList.stream().map(task -> {
                    Order order = new Order();
                    order.setState(1);
                    order.setTime(LocalDateTime.now());
                    order.setUserId(task.getUserId());
                    order.setProductId(task.getProductId());
                    order.setProductTitle(product.getTitle());
                    order.setProductPrice(product.getPrice());
                    order.setProductImg(product.getImg());
                    return order;
                }).collect(Collectors.toList());
                List<Long> userIdList = orderList.stream().map(Order::getUserId).collect(Collectors.toList());
                redisTemplate.opsForList().rightPush("list:seckill:" + product.getId() + ":order", orderList);
                redisTemplate.opsForSet().add("set:seckill:" + product.getId() + ":user", userIdList);
                for (Task task : taskList) {
                    task.getCompletableFuture().complete(Result.success());
                }
            }, 500L);
        }
    }

}
